package leetcode;

/**
 * 91.  解码方法
 * 一条包含字母 A-Z 的消息通过以下映射进行了 编码 ：
 *
 * 'A' -> "1"
 * 'B' -> "2"
 * ...
 * 'Z' -> "26"
 * 要 解码 已编码的消息，所有数字必须基于上述映射的方法，反向映射回字母（可能有多种方法）。例如，"11106" 可以映射为：
 *
 * "AAJF" ，将消息分组为 (1 1 10 6)
 * "KJF" ，将消息分组为 (11 10 6)
 * 注意，消息不能分组为  (1 11 06) ，因为 "06" 不能映射为 "F" ，这是由于 "6" 和 "06" 在映射中并不等价。
 *
 * 给你一个只含数字的 非空 字符串 s ，请计算并返回 解码 方法的 总数 。
 *
 * 题目数据保证答案肯定是一个 32 位 的整数。
 *
 *
 *
 * 示例 1：
 *
 * 输入：s = "12"
 * 输出：2
 * 解释：它可以解码为 "AB"（1 2）或者 "L"（12）。
 * 示例 2：
 *
 * 输入：s = "226"
 * 输出：3
 * 解释：它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。
 * 示例 3：
 *
 * 输入：s = "0"
 * 输出：0
 * 解释：没有字符映射到以 0 开头的数字。
 * 含有 0 的有效映射是 'J' -> "10" 和 'T'-> "20" 。
 * 由于没有字符，因此没有有效的方法对此进行解码，因为所有数字都需要映射。
 *
 *
 *
 * 动态规划
 *
 * dp[i] 表示
 */
public class NumDecodings {
    /**
     *
     * 方法输出为解码总数，不需要具体的解码输出
     *
     * 设 dp[i] 为 s 的前 i 个字符的解码方法总数
     *
     * 伪公式：
     * dp[i] = arr[i-1] !=0
     * ? dp[i-1]
     * :0  +  Integer.parseInt(i-2,i) between (10,26) ? dp[i-2] : 0
     *
     * @param s
     * @return
     */
    public int numDecodings(String s) {


        int n = s.length();
        s = " " + s;
        char[] cs = s.toCharArray();
        int[] dp = new int[n + 1];
        dp[0] = 1;

        // 2 2 6
        // a = 6;b = 26
        for (int i = 1; i <= n; i++) {
            int a = cs[i] - '0';
            int b = (cs[i - 1] - '0') * 10 + (cs[i] - '0');
            int single = 0;
            int double_ = 0;

            // 如果 a 属于有效值，那么 f[i] 可以由 f[i - 1] 转移过来
            if (a != 0){
                single = dp[i - 1];
            }
            // 如果 b 属于有效值，那么 f[i] 可以由 f[i - 2] 或者 f[i - 1] & f[i - 2] 转移过来
            if (10 <= b && b <= 26) {
                double_ = dp[i - 2];
            }
            dp[i] = single + double_;
        }
        return dp[n];
    }

    public static void main(String[] args) {
        String aa = "abc";
        System.out.println(aa.substring(0, 2));

    }
}